package com.jason.lucene.example.search;

import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.Objects;

/**
 * @author he peng
 * @create 2017/12/6 17:07
 * @see
 */
public class PhraseQueryTest {

    protected Directory dir;
    protected IndexSearcher searcher;

    @Before
    public void setUp() throws Exception {
        this.dir = new RAMDirectory();
        IndexWriterConfig writerConf = new IndexWriterConfig(new WhitespaceAnalyzer());
        IndexWriter writer = new IndexWriter(this.dir, writerConf);
        Document doc = new Document();
        doc.add(new Field("field" , "the quick brown fox jumped over the lazy dog" , TextField.TYPE_STORED));
        writer.addDocument(doc);
        writer.close();

        this.searcher = new IndexSearcher(DirectoryReader.open(this.dir));
    }

    @After
    public void tearDown() throws Exception {
        if (Objects.nonNull(this.dir)) {
            this.dir.close();
        }
        if (Objects.nonNull(this.searcher) && Objects.nonNull(this.searcher.getIndexReader())) {
            this.searcher.getIndexReader().close();
        }
    }

    @Test
    public void testSlopComparison() throws Exception {
        String[] phrase = {"quick" , "fox"};
        Assert.assertFalse("exact phrase not found" , matched(phrase , 0));
        Assert.assertTrue("close enough" , matched(phrase , 1));
    }

    /**
     * 项的先后顺序不同情况 , quick fox 需要 slop 为 1 的移动和原文档匹配 ，
     * fox quick 需要 slop 为 3 的移动才和原文档匹配
     * @throws Exception
     */
    @Test
    public void testReverse() throws Exception {
        String[] phrase = {"fox" , "quick"};
        Assert.assertFalse("hop flop" , matched(phrase , 2));
        Assert.assertTrue("hop hop slop" , matched(phrase , 3));
    }

    /**
     * 复合项短语 TODO 没搞明白
     * @throws Exception
     */
    @Test
    public void testMultiple() throws Exception {
        Assert.assertFalse("not close enough" , matched(new String[]{"quick" , "jumped" , "lazy"} , 3));
        Assert.assertTrue("just enough" , matched(new String[]{"quick" , "jumped" , "lazy"} , 4));
        Assert.assertFalse("almost but not quite" , matched(new String[]{"lazy" , "jumped" , "quick"} , 7));
        Assert.assertTrue("bingo" , matched(new String[]{"lazy" , "jumped" , "quick"} , 8));
    }

    private boolean matched(String[] phrase , int slop) throws IOException {
        PhraseQuery.Builder phraseQueryBuilder = new PhraseQuery.Builder().setSlop(slop);
        for (String word : phrase) {
            phraseQueryBuilder.add(new Term("field" , word));
        }

        PhraseQuery phraseQuery = phraseQueryBuilder.build();
        System.err.println("query =====> " + phraseQuery);
        TopDocs topDocs = this.searcher.search(phraseQuery, 1000);
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            System.err.println("hit doc =====> " + this.searcher.doc(scoreDoc.doc));
        }

        return topDocs.totalHits > 0;
    }
}
